package btree;

import java.io.IOException;

import bufmgr.HashEntryNotFoundException;
import bufmgr.InvalidFrameNumberException;
import bufmgr.PageUnpinnedException;
import bufmgr.ReplacerException;

import exceptions.*;
import global.GlobalConst;
import global.PageId;
import global.RID;
import global.SystemDefs;

public class BTFileScan extends IndexFileScan implements GlobalConst {
	// ---------------------------variables---------------------------
	private boolean currentDeleted;
	private boolean scanFirst;
	private BTreeFile bfile;
	// leaf page containing current record
	BTLeafPage leafPage;
	// position in current leaf; note: this is
	// the RID of the key/RID pair within the
	// leaf page.
	private RID curRid;
	private KeyClass endkey;
	private int keyType;
	private int maxKeysize;

	// ----------------------------constructors----------------------
	public BTFileScan(BTreeFile btree, BTLeafPage leafPage, RID curRid,
			KeyClass endkey, int keyType, int maxKeysize) {
		super();
		this.bfile = btree;
		this.leafPage = leafPage;
		this.curRid = curRid;
		this.endkey = endkey;
		this.keyType = keyType;
		this.maxKeysize = maxKeysize;
	}

	public BTFileScan() {
		// TODO Auto-generated constructor stub
	}

	// ---------------------------setters and
	// getters--------------------------------------

	public boolean isCurrentDeleted() {
		return currentDeleted;
	}

	public void setCurrentDeleted(boolean currentDeleted) {
		this.currentDeleted = currentDeleted;
	}

	public boolean isScanFirst() {
		return scanFirst;
	}

	public void setScanFirst(boolean scanFirst) {
		this.scanFirst = scanFirst;
	}

	public BTreeFile getBtree() {
		return bfile;
	}

	public void setBtree(BTreeFile bfile) {
		this.bfile = bfile;
	}

	public BTLeafPage getLeafPage() {
		return leafPage;
	}

	public void setLeafPage(BTLeafPage leafPage) {
		this.leafPage = leafPage;
	}

	public RID getCurRid() {
		return curRid;
	}

	public void setCurRid(RID curRid) {
		this.curRid = curRid;
	}

	public KeyClass getEndkey() {
		return endkey;
	}

	public void setEndkey(KeyClass endkey) {
		this.endkey = endkey;
	}

	public int getKeyType() {
		return keyType;
	}

	public void setKeyType(int keyType) {
		this.keyType = keyType;
	}

	public int getMaxKeysize() {
		return maxKeysize;
	}

	public void setMaxKeysize(int maxKeysize) {
		this.maxKeysize = maxKeysize;
	}

	// ------------------------------------Methods-------------------------
	public KeyDataEntry get_next() {
		KeyDataEntry curentry;
		PageId nextPage;
		
		try {
			if (leafPage == null)
				return null;

			if ((currentDeleted && scanFirst)
					|| (!scanFirst && !currentDeleted)) {
				// still in record which leaf page point
				scanFirst = true;
				currentDeleted = false;

				curentry = leafPage.getCurrent(curRid);

			} else {
				curentry = leafPage.getNext(curRid);
			}
			// page is empty
			while (curentry == null) {
				// get next leaf page
				nextPage = leafPage.getNextPage();
				// unpin last page
				SystemDefs.JavabaseBM.unpinPage(leafPage.getCurPage(), true);
				
				if (nextPage.pid == INVALID_PAGE) {
					// set leaf Page
					leafPage = null;
					return null;
				}
				leafPage = new BTLeafPage(nextPage, keyType);
				curentry = leafPage.getFirst(curRid);

			}
			// here w get the page but not proper page ,must get page with
			// proper key
			if (endkey != null)
				if (BT.keyCompare(curentry.key, endkey) > 0) {
					// went past right end of scan
					SystemDefs.JavabaseBM.unpinPage(leafPage.getCurPage(),
							false);
					leafPage = null;
					return null;
				}

			return curentry;
		} catch (Exception e) {
			e.printStackTrace();

			try {
				throw new ScanIteratorException();
			} catch (ScanIteratorException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}

		}
		return null;
	}

	@Override
	public void delete_current() {
		KeyDataEntry entry;
		try {
			// ------------first case--------------------------------
			if (leafPage == null) {
				System.out.println("No Record to delete!");
				throw new ScanDeleteException();
			}
			// ------------------second case--------------------------
			// --------------------page is already deleted------------
			if ((currentDeleted == true) || (scanFirst == false))
				return;
			// --------------get entry wanted to be deleted------------
			entry = leafPage.getCurrent(curRid);
			SystemDefs.JavabaseBM.unpinPage(leafPage.getCurPage(), false);
			bfile.Delete(entry.key, ((LeafData) entry.data).getData());
			// update leaf page
			leafPage = bfile.getFirstLeafPage(entry.key, curRid);

			currentDeleted = true;
			return;
		} catch (Exception e) {
			e.printStackTrace();
			try {
				throw new ScanDeleteException();
			} catch (ScanDeleteException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
		}

	}

	@Override
	public int keysize() {

		return maxKeysize;
	}

	public void DestroyBTreeFileScan() throws IOException,
			InvalidFrameNumberException, ReplacerException,
			PageUnpinnedException, HashEntryNotFoundException {
		if (leafPage != null) {
			SystemDefs.JavabaseBM.unpinPage(leafPage.getCurPage(), true);
		}
		leafPage = null;
	}
}
